/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tomasio.projects.lua.dao;

import com.tomasio.projects.lua.exception.DAOException;
import com.tomasio.projects.lua.model.User;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.naming.Name;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.support.LdapNameBuilder;
import sun.misc.BASE64Encoder;

/**
 *
 * @author fernandofot
 */
public class SpringLDAPUserDAO implements UserDAO {

    public static final String BASE_DN = "dc=decea,dc=intraer";

    private LdapTemplate ldapTemplate;

    public void setLdapTemplate(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
    }

    @Override
    public String create(User user) throws DAOException {
        DirContextAdapter context = new DirContextAdapter(buildDn(user));
        mapToContext(user, context);
        ldapTemplate.bind(context);
        return user.getUid();
    }

    @Override
    public void remove(String uid) throws DAOException {
        User user = find(uid);
        ldapTemplate.unbind(buildDn(user));
    }

    @Override
    public void update(User user) throws DAOException {
        Name dn = buildDn(user);
        DirContextOperations context = ldapTemplate.lookupContext(dn);
        mapToContext(user, context);
        ldapTemplate.modifyAttributes(context);
    }

    @Override
    public List<User> findAll() throws DAOException {
        EqualsFilter filter = new EqualsFilter("objectclass", "inetOrgPerson");
        Name usersPath = LdapNameBuilder.newInstance()
                .add("ou", "people")
                .build();
        return ldapTemplate.search(usersPath, filter.encode(), getContextMapper());
    }

    @Override
    public List<User> search(String term) throws DAOException {
        EqualsFilter filter = new EqualsFilter("objectclass", "inetOrgPerson");
        Name usersPath = LdapNameBuilder.newInstance()
                .add("ou", "people")
                .build();
        return ldapTemplate.search(usersPath, filter.encode(), getContextMapper());
    }

    @Override
    public User find(String uid) throws DAOException {
        Name dn = buildDn(uid);
        return (User) ldapTemplate.lookup(dn, getContextMapper());
    }

    protected ContextMapper getContextMapper() {
        return new UserContextMapper();
    }

    protected Name buildDn(User user) {
        return buildDn(user.getUid());
    }

    protected Name buildDn(String uid) {
        return LdapNameBuilder.newInstance()
                .add("ou", "people")
                .add("uid", uid)
                .build();
    }

    protected void mapToContext(User user, DirContextOperations context) {
        context.setAttributeValues("objectclass", new String[]{"inetOrgPerson"});
        context.setAttributeValue("cn", user.getName());
        context.setAttributeValue("mail", user.getEmail());
        context.setAttributeValue("givenname", user.getGivenName());
        context.setAttributeValue("o", user.getOrganization());
        context.setAttributeValue("userpassword", "{SHA}" + encrypt(user.getPassword()));
        context.setAttributeValue("sn", user.getSurname());
        context.setAttributeValue("title", user.getTitle());
        context.setAttributeValue("telephonenumber", user.getPhoneNumber());

    }

    private static class UserContextMapper extends AbstractContextMapper<User> {

        @Override
        public User doMapFromContext(DirContextOperations context) {
            User u = new User();
            u.setUid(context.getStringAttribute("uid"));
            u.setName(context.getStringAttribute("cn"));
            u.setEmail(context.getStringAttribute("mail"));
            u.setGivenName(context.getStringAttribute("givenname"));
            u.setLogin(context.getStringAttribute("uid"));
            u.setOrganization(context.getStringAttribute("o"));
            
            u.setSurname(context.getStringAttribute("sn"));
            u.setTitle(context.getStringAttribute("title"));
            u.setPhoneNumber(context.getStringAttribute("telephonenumber"));

            return u;
        }

    }

    private String encrypt(final String plaintext) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e.getMessage());
        }
        try {
            md.update(plaintext.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage());
        }
        byte raw[] = md.digest();
        String hash = (new BASE64Encoder()).encode(raw);
        return hash;

    }

}
